package org.geotools.tutorial.quickstart;

import org.geotools.data.*;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.data.JFileDataStoreChooser;
import org.geotools.swing.styling.JSimpleStyleDialog;
import org.geotools.tutorial.quickstart.DataStoreNode.SchemaNode;
import org.geotools.tutorial.quickstart.DataStoreNode.SchemaNodes;
import org.geotools.tutorial.quickstart.DataStoreNode.SchemaType;
import org.geotools.tutorial.quickstart.UI.DialogAttributeTable;
import org.geotools.tutorial.quickstart.UI.DialogGeopackageLoader;
import org.geotools.tutorial.quickstart.UI.DialogHbaseLoader;
import org.geotools.tutorial.quickstart.UI.DialogPostgisLoader;
import org.geotools.tutorial.quickstart.Utilities.DataStoreUtilities;
import org.geotools.tutorial.quickstart.Utilities.GridBagConstraintsHelper;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureVisitor;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;

import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author
 * @DesktopJavaDocable disable
 */
public class JMainFrame extends JFrame {

	private DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("DataStore");

	private JTree jTree = new JTree(rootNode);
	private JPanel panel = new JPanel();
	private Button buttonShapeFile = new Button("ShapeFile");
	private Button buttonPostgis = new Button("Postgis");
	private Button buttonHbase = new Button("Hbase");
	private Button buttonGeoPackage = new Button("GeoPackage");
	private Button buttonImport = new Button("Import");
	private JMapFrame jMapFrame;

	public JMainFrame() {
		initLayout();
		initParams();
	}

	private void initLayout() {

		JToolBar toolBar = new JToolBar();
		toolBar.setLayout(new GridBagLayout());
		toolBar.add(buttonShapeFile, new GridBagConstraintsHelper(0, 0, 1, 1).setFill(GridBagConstraints.HORIZONTAL).setWeight(1, 1).setInsets(2));
		toolBar.add(buttonPostgis, new GridBagConstraintsHelper(1, 0, 1, 1).setFill(GridBagConstraints.HORIZONTAL).setWeight(1, 1).setInsets(2));
		toolBar.add(buttonHbase, new GridBagConstraintsHelper(2, 0, 1, 1).setFill(GridBagConstraints.HORIZONTAL).setWeight(1, 1).setInsets(2));
		toolBar.add(buttonGeoPackage, new GridBagConstraintsHelper(3, 0, 1, 1).setFill(GridBagConstraints.HORIZONTAL).setWeight(1, 1).setInsets(2));
		toolBar.add(buttonImport, new GridBagConstraintsHelper(4, 0, 1, 1).setFill(GridBagConstraints.HORIZONTAL).setWeight(1, 1).setInsets(2));
		this.panel.setLayout(new BorderLayout());
		this.panel.add(toolBar, BorderLayout.NORTH);
		this.panel.add(jTree, BorderLayout.CENTER);
		this.getContentPane().setLayout(new BorderLayout());
		this.getContentPane().add(new Panel(), BorderLayout.NORTH);
		this.getContentPane().add(new Panel(), BorderLayout.WEST);
		this.getContentPane().add(new Panel(), BorderLayout.SOUTH);
		this.getContentPane().add(new Panel(), BorderLayout.EAST);
		this.getContentPane().add(this.panel, BorderLayout.CENTER);
	}

	private void initParams() {
		jTree.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				super.mouseClicked(e);
				TreePath selPath = jTree.getPathForLocation(e.getX(), e.getY());
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent();
				if (e.getClickCount() == 1) {
					if (node.children() != null) {
						jTree.expandPath(selPath);
					}
				} else if (e.getClickCount() == 2) {

					if (node.getParent() != null) {
						if (node instanceof SchemaNode) {
							SchemaNode schemaNode = (SchemaNode) node;
							SchemaType type = schemaNode.getSchemaType();
							if (type == SchemaType.SHAPEFILE) {
								openShapeFileSchema(schemaNode);
							} else if (type == SchemaType.POSTGIS) {
								openFeatureSource(schemaNode);
							} else if (type == SchemaType.HBASE) {
								openFeatureSource(schemaNode);
							} else if (type == SchemaType.GEOPACKAGE) {
								openFeatureSource(schemaNode);
							}
						}
						jTree.expandPath(selPath);
					}
				}
			}
		});

		buttonShapeFile.addActionListener((e) -> {
			openShapeFileDatastore();
		});

		buttonPostgis.addActionListener((e) -> {
			openPostgisDatastore();
		});

		buttonHbase.addActionListener((e) -> {
			ListAvailableDataStores();
			openHbaseDatastore();
		});

		buttonGeoPackage.addActionListener((e) -> {
			openGeopackageDatastore();
		});

		buttonImport.addActionListener((e) -> {
			importFeature();
		});

		expandAll(jTree, new TreePath(rootNode), true);

		MapContent mapContent = new MapContent();
		mapContent.setTitle("DataStore Demo");
		jMapFrame = new JMapFrame(mapContent);
	}

	private void openShapeFileDatastore() {
		JFileChooser jFileChooser = new JFileChooser();
		FileSystemView fsv = FileSystemView.getFileSystemView();
		jFileChooser.setCurrentDirectory(fsv.getDefaultDirectory());
		jFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		if (jFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
			File dirctory = jFileChooser.getSelectedFile();
			SchemaNodes schemaNodes = new SchemaNodes(dirctory, SchemaType.SHAPEFILE, dirctory.getPath());
			File[] files = dirctory.listFiles();
			for (File file : files) {
				if (file.getAbsolutePath().endsWith("shp")) {
					schemaNodes.add(new SchemaNode(file, SchemaType.SHAPEFILE, file.getName().substring(0, file.getName().indexOf("."))) {
					});
				}
			}
			rootNode.add(schemaNodes);
			jTree.updateUI();
			expandAll(jTree, new TreePath(rootNode), true);
		}
	}

	private void openShapeFileSchema(SchemaNode postgisSchema) {
		String fileName = "";
		try {
			if (postgisSchema == null) {
				return;
			}

			File file = new File(((File) postgisSchema.getUserObject()).getPath());
			fileName = file.getName();
			FileDataStore store = FileDataStoreFinder.getDataStore(file);
			if (store == null) {
				return;
			}
			List<Name> names = store.getNames();
			Query query1 = new Query(names.get(0).toString(), Filter.INCLUDE);
			FeatureReader<SimpleFeatureType, SimpleFeature> featureReader = store.getFeatureReader(query1, Transaction.AUTO_COMMIT);
			while (featureReader.hasNext()) {
				SimpleFeature next = featureReader.next();
				System.out.println(featureReader.getFeatureType().getTypeName());
				System.out.println(next.getAttribute(2));
			}

			SimpleFeatureSource featureSource = store.getFeatureSource();
			SimpleFeatureIterator simpleFeatureIterator = featureSource.getFeatures().features();
			SimpleFeature simpleFeature = simpleFeatureIterator.next();


			//Create a map content and add our shapefile to it
			MapContent map = new MapContent();
			map.setTitle(fileName.substring(0, fileName.indexOf('.')));
			Style style = JSimpleStyleDialog.showDialog(null, featureSource.getSchema());
			Layer layer = new FeatureLayer(featureSource, style);
			map.addLayer(layer);
			// Now display the map
			showMap(map);

		} catch (IOException e) {
			e.printStackTrace();
			System.out.println(fileName + "打开失败！请检查相关参数");
		}
	}


	private void openPostgisDatastore() {
		String fileName = "";
		try {

			DialogPostgisLoader dialogPostgisLoader = new DialogPostgisLoader(this);
			if (dialogPostgisLoader.showDialog() == DialogPostgisLoader.DialogResult.OK) {
				Map param = dialogPostgisLoader.getParam();
				DataStore dataStore = DataStoreUtilities.getDataStore(param);
				if (dataStore == null) {
					return;
				}
				SchemaNodes schemaNodes = new SchemaNodes(param, SchemaType.POSTGIS, param.values().toArray()[0].toString());
				List<Name> names = dataStore.getNames();
				for (Name name : names) {
					SimpleFeatureType schema = dataStore.getSchema(name);
					GeometryDescriptor geometryDescriptor = schema.getGeometryDescriptor();
					if (geometryDescriptor != null) {
						schemaNodes.add(new SchemaNode(name, SchemaType.POSTGIS, name.toString()) {
						});
					}
				}
				rootNode.add(schemaNodes);
				jTree.updateUI();
				expandAll(jTree, new TreePath(rootNode), true);
				dataStore.dispose();
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(fileName + "打开失败！请检查相关参数");
		}
	}

	private void openHbaseDatastore() {
		String fileName = "";
		try {
			DialogHbaseLoader dialogPostgisLoader = new DialogHbaseLoader(this);
			if (dialogPostgisLoader.showDialog() == DialogHbaseLoader.DialogResult.OK) {
				Map params = dialogPostgisLoader.getParams();
				DataStore dataStore = DataStoreUtilities.getDataStore(params);
				if (dataStore == null) {
					return;
				}
				SchemaNodes schemaNodes = new SchemaNodes(params, SchemaType.HBASE, params.values().toArray()[0].toString());
				List<Name> names = dataStore.getNames();
				for (Name name : names) {

					System.out.println(name.getLocalPart());
					schemaNodes.add(new SchemaNode(name, SchemaType.HBASE, name.toString()) {
					});
				}
				rootNode.add(schemaNodes);
				jTree.updateUI();
				expandAll(jTree, new TreePath(rootNode), true);
				dataStore.dispose();
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(fileName + "打开失败！请检查相关参数");
		}
	}

	private void openGeopackageDatastore() {
		String fileName = "";
		try {
			DialogGeopackageLoader dialogGeopackageLoader = new DialogGeopackageLoader(this);
			if (dialogGeopackageLoader.showDialog() == DialogGeopackageLoader.DialogResult.OK) {
				Map params = dialogGeopackageLoader.getParam();
				DataStore dataStore = DataStoreUtilities.getDataStore(params);
				if (dataStore == null) {
					return;
				}
				SchemaNodes schemaNodes = new SchemaNodes(params, SchemaType.HBASE, params.values().toArray()[0].toString());
				List<Name> names = dataStore.getNames();
				for (Name name : names) {
					schemaNodes.add(new SchemaNode(name, SchemaType.HBASE, name.toString()) {
					});
				}
				rootNode.add(schemaNodes);
				jTree.updateUI();
				expandAll(jTree, new TreePath(rootNode), true);
				dataStore.dispose();
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(fileName + "打开失败！请检查相关参数");
		}
	}

	private void importFeature() {
		try {
			SimpleFeatureSource simpleFeatureSource = null;
			//DialogGeopackageLoader geopackageLoader = new DialogGeopackageLoader(this);
			//if (geopackageLoader.showDialog() == DialogGeopackageLoader.DialogResult.OK) {
			//	Map param = geopackageLoader.getParam();
			//	DataStore sourceDataStore = DataStoreUtilities.getDataStore(param);
			//	simpleFeatureSource = sourceDataStore.getFeatureSource("jbntbhtb123");
			//}
			File file = JFileDataStoreChooser.showOpenFile("shp", null);
			if (file == null) {
				return;
			}
			Charset charset = Charset.forName("UTF-8");
			//ShapefileDataStore store = (ShapefileDataStore) FileDataStoreFinder.getDataStore(file);
			//simpleFeatureSource = store.getFeatureSource();
			DialogHbaseLoader dialogPostgisLoader = new DialogHbaseLoader(this);
			if (dialogPostgisLoader.showDialog() == DialogHbaseLoader.DialogResult.OK) {
				Map param = dialogPostgisLoader.getParams();
				DataStore targetDataStore = DataStoreUtilities.getDataStore(param);
				DataStoreUtilities.ImportShp(simpleFeatureSource, targetDataStore);
			}
			//DialogGeopackageLoader geopackageLoader = new DialogGeopackageLoader(this);
			//if (geopackageLoader.showDialog() == DialogGeopackageLoader.DialogResult.OK) {
			//	Map param = geopackageLoader.getParam();
			//	DataStore targetDataStore = DataStoreUtilities.getDataStore(param);
			//	DataStoreUtilities.ImportShp(simpleFeatureSource, targetDataStore);
			//}


			//DialogPostgisLoader dialogPostgisLoader = new DialogPostgisLoader(this);
			//if(dialogPostgisLoader.showDialog()==DialogPostgisLoader.DialogResult.OK){
			//	Map param = dialogPostgisLoader.getParam();
			//	Iterator<DataStoreFactorySpi> allDataStores = DataStoreFinder.getAllDataStores();
			//	while (allDataStores.hasNext()) {
			//		DataStoreFactorySpi dataStoreFactorySpi = allDataStores.next();
			//		if(dataStoreFactorySpi.canProcess(param)){
			//			String displayName = dataStoreFactorySpi.getDisplayName();
			//			DataStore newDataStore = dataStoreFactorySpi.createNewDataStore(param);
			//			List<Name> names = newDataStore.getNames();
			//		}
			//	}
			//}

			//DialogGeopackageLoader dialogPostgisLoader = new DialogGeopackageLoader(this);
			//if(dialogPostgisLoader.showDialog()==DialogGeopackageLoader.DialogResult.OK){
			//	Map param = dialogPostgisLoader.getParam();
			//	Iterator<DataStoreFactorySpi> allDataStores = DataStoreFinder.getAllDataStores();
			//	while (allDataStores.hasNext()) {
			//		DataStoreFactorySpi dataStoreFactorySpi = allDataStores.next();
			//		if(dataStoreFactorySpi.canProcess(param)){
			//			String displayName = dataStoreFactorySpi.getDisplayName();
			//			DataStore newDataStore = dataStoreFactorySpi.createNewDataStore(param);
			//			List<Name> names = newDataStore.getNames();
			//		}
			//	}
			//}

			//DialogHbaseLoader dialogHbaseLoader = new DialogHbaseLoader(this);
			//if (dialogHbaseLoader.showDialog() == DialogHbaseLoader.DialogResult.OK) {
			//	Map param = dialogHbaseLoader.getParams();
			//	Iterator<DataStoreFactorySpi> allDataStores = DataStoreFinder.getAllDataStores();
			//	while (allDataStores.hasNext()) {
			//		DataStoreFactorySpi dataStoreFactorySpi = allDataStores.next();
			//		if(dataStoreFactorySpi.canProcess(param)){
			//			String displayName = dataStoreFactorySpi.getDisplayName();
			//			DataStore newDataStore = dataStoreFactorySpi.createNewDataStore(param);
			//			List<Name> names = newDataStore.getNames();
			//		}
			//	}
			//}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	class SimpleFeatureVisitor implements FeatureVisitor {
		private int counter = 0;

		public SimpleFeatureVisitor() {
			this.counter = counter;
		}

		public int getCounter() {
			return counter;
		}

		@Override
		public void visit(Feature feature) {
			counter++;
		}
	}


	private void openFeatureSource(SchemaNode schemaNode) {
		try {
			if (schemaNode == null) {
				return;
			}
			SchemaNodes parentNodes = (SchemaNodes) schemaNode.getParent();
			Map params = (Map) parentNodes.getUserObject();
			if (params == null) {
				return;
			}
			String name = ((Name) schemaNode.getUserObject()).toString();
			DataStore dataStore = DataStoreUtilities.getDataStore(params);
			if (dataStore == null) {
				return;
			}
			SimpleFeatureSource featureSource = dataStore.getFeatureSource(name);
			//int count = 0;
			//Query query = new Query(featureSource.getSchema().getTypeName());
			//query.setStartIndex(0);
			//SimpleFeatureCollection features = featureSource.getFeatures(query);
			//int size = features.size();
			//if (featureSource instanceof GeoMesaFeatureSource) {
			//	Query query = new Query();
			//	query.getHints().put(QueryHints.EXACT_COUNT(),Boolean.FALSE);
			//	count = featureSource.getCount(query);
			//} else {
			//	count = featureSource.getCount(Query.ALL);
			//}
			//System.out.println(count);
			//SimpleFeatureIterator featureIterator = featureSource.getFeatures().features();
			//while (featureIterator.hasNext()) {
			//	SimpleFeature simpleFeature = featureIterator.next();
			//	Object attribute = simpleFeature.getAttribute(1);
			//	System.out.println(attribute.toString());
			//	System.out.println("M");
			//}

			//DataStoreUtilities.updateSchema(dataStore, featureSource.getSchema());
			//
			//subSimpleFeatureCollection(featureSource);
			//Create a map content and add our shapefile to it
			MapContent map = new MapContent();
			map.setTitle(name);
			Style style = SLD.createSimpleStyle(featureSource.getSchema());
			Layer layer = new FeatureLayer(featureSource, style);
			map.addLayer(layer);
			//
			//// Now display the map
			showMap(map);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("打开失败！请检查相关参数");
		}
	}

	private void subSimpleFeatureCollection(SimpleFeatureSource simpleFeatureSource) {
		try {
			SimpleFeatureCollection simpleFeatureCollection = DataStoreUtilities.subFeatureCollection(simpleFeatureSource, 0, 100);
			DialogAttributeTable attributeTable = new DialogAttributeTable(this, simpleFeatureSource.getName().toString(), simpleFeatureCollection);
			attributeTable.showDialog();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	private void showMap(MapContent content) {
		jMapFrame.setMapContent(content);

		if (!jMapFrame.isVisible()) {
			jMapFrame.enableStatusBar(true);
			jMapFrame.enableToolBar(true);
			jMapFrame.enableLayerTable(true);
			jMapFrame.initComponents();
			jMapFrame.setSize(1350, 1000);
			jMapFrame.setVisible(true);
		}
	}

	public void startShow() {
		this.setTitle("Catalog");
		this.setSize(480, 1000);
		this.setLocationRelativeTo(null);
		super.show();
	}

	private void expandAll(JTree tree, TreePath parent, boolean expand) {
		// Traverse children
		TreeNode node = (TreeNode) parent.getLastPathComponent();
		if (node.getChildCount() >= 0) {
			for (Enumeration e = node.children(); e.hasMoreElements(); ) {
				TreeNode n = (TreeNode) e.nextElement();
				TreePath path = parent.pathByAddingChild(n);
				expandAll(tree, path, expand);
			}
		}
		if (expand) {
			tree.expandPath(parent);
		} else {
			tree.collapsePath(parent);
		}
	}

	private void ListAvailableDataStores() {
		//Finds all implemtaions of DataStoreFactory which have registered using the services mechanism,
		// regardless weather it has the appropriate libraries on the classpath.
		Iterator<DataStoreFactorySpi> availableDataStores = DataStoreFinder.getAvailableDataStores();
		while (availableDataStores.hasNext()) {
			DataStoreFactorySpi dataStoreFactorySpi = availableDataStores.next();
			//获取参数列表
			DataAccessFactory.Param[] parametersInfo = dataStoreFactorySpi.getParametersInfo();
		}
	}


}

